package com.gitee.wsl.common.chart.render.background.axis.round

import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.PointF
import com.gitee.wsl.android.ext.math.calcArcEndPointXY
import com.gitee.wsl.common.chart.ChartEnum
import com.gitee.wsl.common.chart.render.background.axis.BaseAxis
import com.gitee.wsl.android.ui.ext.type.*
import com.gitee.wsl.common.ui.draw.type.Location
import com.gitee.wsl.ext.list.setAll
import com.gitee.wsl.transform.format.Format
import com.gitee.wsl.math.Math
import com.gitee.wsl.jvm.math.add
import com.gitee.wsl.jvm.math.div
import com.gitee.wsl.jvm.math.mul

import timber.log.Timber

/**
 * @ClassName DialChart
 * @Description  仪表盘基类
 * @author XiongChuanLiang<br/>(xcl_168@aliyun.com)
 *
 */
class RoundAxis: BaseAxis() {
    // private static final String TAG ="RoundAxis";
    var cirX = 0.0f
    var cirY = 0.0f

    val dataSet = mutableListOf<Float>()

    var orgRadius = 0.0f
    var radius = 0.0f
    var detailModeSteps = 1

    var radiusPercentage = 1f
    var innerRadiusPercentage = 0.9f

    // 用于格式化标签的回调接口
    var labelFormatter: Format<String>? = null

    var totalAngle = 0.0f
    var initAngle = 0.0f
    var axisType = ChartEnum.RoundAxisType.ARCLINEAXIS

    val colorList = mutableListOf<Int>()
    val labels = mutableListOf<String>()

    //ringaxis/fillaxis
    val fillAxisPaint: Paint by lazy {
        Paint().apply {
            style = Paint.Style.FILL
            color = Color.WHITE
            isAntiAlias = true
        }
    }

    var isLongTickfakeBold = true
    //  float mShortTickPercentage = 0.95f;

    //  float mShortTickPercentage = 0.95f;
    var roundTickAxisType = ChartEnum.RoundTickAxisType.INNER_TICKAXIS

    var location = Location.BOTTOM
    //线的风格(点或线之类)
    //private ChartEnum.LineStyle mLineStyle = ChartEnum.LineStyle.SOLID;
    //设置线箭头 (三角，方形，棱形....)  
    //private ChartEnum.DotStyle mLineCap = ChartEnum.DotStyle.HIDE;

    /**
     * 外环半径长度
     * @return    半径长度
     */
    val outerRadius: Float
        get() {
            return orgRadius * radiusPercentage
        }

    /**
     * 内环半径长度
     * @return    半径长度
     */
    val ringInnerRadius: Float
        get() {
            return orgRadius * innerRadiusPercentage
        }

    
    fun setDetailModeSteps(
        steps: Int,
        isLongTickfakeBold: Boolean
    ) {
        detailModeSteps = steps
        this.isLongTickfakeBold = isLongTickfakeBold
    }

    fun setAxisPercentage(angle: List<Float>) {
        dataSet.setAll(angle)
    }

    fun setAxisColor(color: List<Int>) {
        colorList.setAll( color)
    }

    fun setAxisLabels(labels: List<String>) {
        this.labels.setAll(labels)
    }

    /**
     * 返回标签显示格式
     *
     * @param value 传入当前值
     * @return 显示格式
     */
    protected  fun getFormatterLabel(text: String): String {
        return labelFormatter?.invoke(text)?:text
    }
    
    
    /**
     * 设置轴类型,不同类型有不同的显示风格
     * @param axisType 轴类型
     */
    fun setRoundAxisType(axisType: ChartEnum.RoundAxisType) {
        this.axisType = axisType
        when (this.axisType) {
            ChartEnum.RoundAxisType.TICKAXIS -> {
                tickLabelPaint.textAlign = Paint.Align.CENTER
                isAxisLabelsVisible = true
                isTickMarksVisible = true
                isAxisLineVisible = true
                this.axisPaint.style = Paint.Style.STROKE
            }
            ChartEnum.RoundAxisType.RINGAXIS -> {
                isAxisLabelsVisible = true
                isTickMarksVisible = false
                this.axisPaint.style = Paint.Style.FILL
                this.axisPaint.color = Color.BLUE
            }
            ChartEnum.RoundAxisType.ARCLINEAXIS -> {
                isAxisLabelsVisible = false
                isTickMarksVisible = false
                axisPaint.style = Paint.Style.STROKE
                //mPaintAxis.setStyle(Style.FILL);
            }
            ChartEnum.RoundAxisType.CIRCLEAXIS -> {
                isAxisLabelsVisible = false
                isTickMarksVisible = false
            }
            else -> {}
        }
    }

    /**
     * 绘制标签环形轴标签
     * @param canvas    画布
     * @param labels    标签集合
     * @return    是否绘制成功
     */
    fun drawTicks(canvas: Canvas, labels: List<String>): Boolean {
        val cirX = cirX
        val cirY = cirY
        val count = labels.size
        var stepsAngle = 0f
        stepsAngle = if (totalAngle.compareTo(360f) == 0) {
            Math.div(totalAngle, count.toFloat())
        } else {
            Math.div(totalAngle, (count - 1).toFloat())
        }
        val innerRadius1 = radius
        var tickRadius = 0.0f
        var detailRadius = 0.0f
        if (ChartEnum.RoundTickAxisType.INNER_TICKAXIS == roundTickAxisType) {
            tickRadius = radius * 0.95f
            detailRadius = tickRadius

            //有启用主明细步长设置 (inner)
            if (1 < detailModeSteps) tickRadius -= radius * 0.05f
        } else {
            tickRadius = radius + radius * 0.05f
            detailRadius = tickRadius
            if (1 < detailModeSteps) tickRadius = radius + radius * 0.08f
        }
        var steps = detailModeSteps
        var Angle = 0.0f
        val tickMarkWidth: Float = tickMarkPaint.strokeWidth
        var stopX = 0.0f
        var stopY = 0.0f
        var labelX = 0.0f
        var labelY = 0.0f
        var startX = 0.0f
        var startY = 0.0f
        for (i in 0 until count) {
            Angle = if (0 == i) {
                initAngle
            } else {
                //Angle =  add(Angle,stepsAngle);
                Math.add(initAngle, i * stepsAngle)
            }
            var pointF= Math.calcArcEndPointXY(cirX, cirY, innerRadius1, Angle)
            startX = pointF.x
            startY = pointF.y
            stopY = 0.0f
            stopX = stopY
            labelY = 0.0f
            labelX = labelY
            pointF= Math.calcArcEndPointXY(cirX, cirY, tickRadius, Angle)
            labelX = pointF.x
            labelY = pointF.y
            if (steps == detailModeSteps) {
                stopX = labelX
                stopY = labelY
                steps = 0
            } else {
                pointF= Math.calcArcEndPointXY(cirX, cirY, detailRadius, Angle)
                stopX = pointF.x
                stopY = pointF.y
                steps++
            }
            if (isTickMarksVisible) {
                if (0 == steps && isLongTickfakeBold) {
                    tickMarkPaint.strokeWidth = tickMarkWidth + 1
                } else {
                    if (isLongTickfakeBold) tickMarkPaint.strokeWidth = tickMarkWidth
                }
                canvas.drawLine(startX, startY, stopX, stopY, tickMarkPaint)
            }
            if (isAxisLabelsVisible) {
                //回调函数定制化标签显示格式
                val label: String = getFormatterLabel(labels[i])
                val pLabel = getLabelXY(label, labelX, labelY, cirX, cirY, totalAngle, Angle)

                //标签显示
                canvas.drawRotateText(
                    label, pLabel.x, pLabel.y,
                    tickLabelRotateAngle,  tickLabelPaint
                )
            }
        } //end for
        return true
    }

    //得到标签显示位置
    private fun getLabelXY(
        label: String, defLabelX: Float, defLabelY: Float,
        cirX: Float, cirY: Float, totalAngle: Float, Angle: Float
    ): PointF {
        val pLabel = PointF(defLabelX, defLabelY)
        val labelWidth = tickLabelPaint.textWidth(label)
        val labelHeight = tickLabelPaint.textHeight
        tickLabelPaint.textAlign = Paint.Align.CENTER
        if (ChartEnum.RoundTickAxisType.INNER_TICKAXIS == roundTickAxisType) {
            if (pLabel.y.compareTo(cirY) == 0) {
                if (pLabel.x.compareTo(cirX) == -1) {
                    pLabel.x += labelWidth / 2
                } else {
                    pLabel.x -= labelWidth / 2
                }
            } else if (pLabel.x.compareTo(cirX) == 0) {
                if (pLabel.y.compareTo(cirY) == -1) {
                    pLabel.y += labelHeight / 2
                } else {
                    pLabel.y -= labelHeight / 2
                }
            } else if (totalAngle.compareTo(Angle) == 0) {
                pLabel.y += labelHeight
            } else if (pLabel.x.compareTo(cirX) == 1) {
                if (totalAngle.compareTo(360f) == 0) {
                    tickLabelPaint.textAlign = Paint.Align.RIGHT
                } else {
                    pLabel.x -= labelWidth / 2
                }
            } else if (pLabel.x.compareTo(cirX) == -1) {
                if (totalAngle.compareTo(360f) == 0) {
                    tickLabelPaint.textAlign = Paint.Align.LEFT
                } else {
                    pLabel.x += labelWidth / 2
                }
            }
        } else {
            if (pLabel.y.compareTo(cirY) == 0) {
                if (pLabel.x.compareTo(cirX) == -1) {
                    pLabel.x -= labelWidth / 2
                } else {
                    pLabel.x += labelWidth / 2
                }
            } else if (pLabel.x.compareTo(cirX) == 0) {
                if (pLabel.y.compareTo(cirY) == -1) {
                    pLabel.y -= labelHeight / 2
                } else {
                    pLabel.y += labelHeight / 2
                }
            } else if (totalAngle.compareTo(Angle) == 0) {
                pLabel.y -= labelHeight
            } else if (pLabel.x.compareTo(cirX) == 1) {
                if (totalAngle.compareTo(360f) == 0) {
                    tickLabelPaint.textAlign = Paint.Align.LEFT
                } else {
                    pLabel.x += labelWidth / 2
                }
            } else if (pLabel.x.compareTo(cirX) == -1) {
                if (totalAngle.compareTo(360f) == 0) {
                    tickLabelPaint.textAlign = Paint.Align.RIGHT
                } else {
                    pLabel.x -= labelWidth / 2
                }
            }
        }
        return pLabel
    }

    //fillAxis
    /**
     * 绘制填充环形轴
     * @param canvas 画布
     * @return 是否成功
     * @throws Exception 例外
     */
    @Throws(Exception::class)
    fun drawFillAxis(canvas: Canvas): Boolean {
        if (isAxisVisible && isAxisLineVisible) {
            if(colorList.size>0) fillAxisPaint.color = colorList[0]
            canvas.drawPercentArc(
                 this.fillAxisPaint,
                cirX, cirY, radius, initAngle, totalAngle, true
            )
        }
        return true
    }

    /**
     * 绘制标签环形轴
     * @param canvas
     * @return
     * @throws Exception
     */
    @Throws(Exception::class)
    fun drawTickAxis(canvas: Canvas): Boolean {
        if (!isAxisVisible) return false
        if (labels.isEmpty()) return false
        if (isAxisLineVisible) {
            canvas.drawPathArc(
                 this.axisPaint,
                cirX, cirY, radius, initAngle, totalAngle
            )
        }
        return drawTicks(canvas, labels)
    }

    //arcline
    /**
     * 绘制弧形环形轴
     * @param canvas
     * @return
     * @throws Exception
     */
    @Throws(Exception::class)
    fun drawArcLineAxis(canvas: Canvas): Boolean {
        if (isAxisVisible && isAxisLineVisible) {
            canvas.drawPathArc(
                 this.axisPaint, cirX, cirY, radius, initAngle, totalAngle
            )
        }
        return true
    }

    @Throws(Exception::class)
    fun drawCircleAxis(canvas: Canvas): Boolean {
        if (isAxisVisible && isAxisLineVisible) {
            if (colorList.size>0) axisPaint.color = colorList[0]
            canvas.drawCircle(cirX, cirY, radius, this.axisPaint)
        }
        return true
    }


    /**
     * 绘制颜色块环形轴
     * @param canvas 画布
     * @return  结果
     * @throws Exception 例外
     */
    @Throws(Exception::class)
    fun drawRingAxis(canvas: Canvas): Boolean {
        if (!isAxisVisible || !isAxisLineVisible) return true
        if (dataSet.isEmpty()) return false
        var angleCount = 0
        var colorCount = 0
        var labelsCount = 0
        angleCount = dataSet.size
        colorCount = colorList.size
        labelsCount = labels.size
        var offsetAngle = initAngle
        var currentColor = -1
        var currentLabel = ""
        var sweepAngle = 0.0f
        for (i in 0 until angleCount) {
            if ( colorCount > i) currentColor = colorList[i]
            if ( labelsCount > i) currentLabel = labels[i]
            sweepAngle =  Math.mul(totalAngle, dataSet[i])
            drawPartitions(canvas, offsetAngle, sweepAngle, currentColor, currentLabel)
            offsetAngle =  Math.add(offsetAngle, sweepAngle)
            currentColor = -1
            currentLabel = ""
        }
        if (innerRadiusPercentage.compareTo(0.0f) != 0 && innerRadiusPercentage.compareTo(0.0f) == 1) {
            canvas.drawCircle(
                cirX, cirY,
                ringInnerRadius, this.fillAxisPaint
            )
        }
        return true
    }
    
    
    /**
     * 绘制颜色轴
     * @throws Exception
     */
    @Throws(Exception::class)
    private fun drawPartitions(
        canvas: Canvas, startAngle: Float, sweepAngle: Float,
        color: Int, label: String
    ): Boolean {

        //if(color >= -1) 
        axisPaint.color = color
        if (sweepAngle.compareTo(0.0f) < 0) {
            Timber.d("负角度???!!!")
            return false
        } else if (sweepAngle.compareTo(0.0f) == 0) {
            Timber.d( "零角度???!!!")
            return true
        }
        canvas.drawPercentArc(
            this.axisPaint,
            cirX, cirY, radius,
            startAngle, sweepAngle, true
        )
        if (isAxisLabelsVisible && "" !== label) {
            val angle =  Math.add(startAngle, sweepAngle / 2)
            val point= Math.calcArcEndPointXY(
                cirX, cirY,
                radius * 0.5f, angle
            )
            val labelX = point.x
            val labelY = point.y

            //定制化显示格式	 Angle* -2
            canvas.drawRotateText(
                getFormatterLabel(label), labelX, labelY,
                tickLabelRotateAngle, tickLabelPaint
            )
        }
        return true
    }

    /**
     * 设置线的风格(点或线之类)
     * @param style 线的风格
     */
    /*
		public void setLineStyle(ChartEnum.LineStyle  style)
		{
			mLineStyle = style;
		}
		
		// 设置线箭头 (三角，方形，棱形....)  
		public void setLineCap(ChartEnum.DotStyle style) {
			this.mLineCap = style;
		}
		*/
    /**
     * 中心点的线轴
     * @param canvas 画布
     * @return    结果
     * @throws Exception 例外
     */
    fun drawLineAxis(canvas: Canvas): Boolean {
        if (!isAxisVisible || !isAxisLineVisible) return true
        when (location) {
            Location.TOP ->
                canvas.drawLine(cirX, cirY, cirX, cirY - radius, this.axisPaint)
            Location.BOTTOM ->
                canvas.drawLine(cirX, cirY, cirX, cirY + radius, this.axisPaint)
            Location.LEFT ->
                canvas.drawLine(cirX, cirY, cirX - radius, cirY, this.axisPaint)
            Location.RIGHT ->
                canvas.drawLine(cirX, cirY, cirX + radius, cirY, this.axisPaint)
            else -> return false
        }
        return true
    }

    /**
     * 圆心坐标
     * @param x x坐标
     * @param y    y坐标
     */
    fun setCenterXY(x: Float, y: Float) {
        cirX = x
        cirY = y
    }

    /**
     * Ploat范围半径
     * @param radius
     */
    @JvmName("setOrgRadius1")
    fun setOrgRadius(radius: Float) {
        orgRadius = radius
    }

    /**
     * 指定角度及偏移
     * @param totalAngle    总角度
     * @param initAngle        偏移
     */
    fun setAngleInfo(totalAngle: Float, initAngle: Float) {
        this.totalAngle = totalAngle
        this.initAngle = initAngle
    }
    

    /**
     * 绘制图表
     * @param canvas    画布
     * @return    是否成功
     * @throws Exception    例外
     */
    @Throws(Exception::class)
    fun render(canvas: Canvas): Boolean {
        var ret = false
        radius = outerRadius
        ret = when (axisType) {
            ChartEnum.RoundAxisType.TICKAXIS -> drawTickAxis(canvas)
            ChartEnum.RoundAxisType.RINGAXIS -> drawRingAxis(canvas)
            ChartEnum.RoundAxisType.ARCLINEAXIS -> drawArcLineAxis(canvas)
            ChartEnum.RoundAxisType.FILLAXIS -> drawFillAxis(canvas)
            ChartEnum.RoundAxisType.CIRCLEAXIS -> drawCircleAxis(canvas)
            ChartEnum.RoundAxisType.LINEAXIS -> drawLineAxis(canvas)
        }
        return ret
    }
}